/*
 * main.c
 *
 *  Created on: 14 nov. 2012
 *      Author: David Charbonnier, Imad Wakidi
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Définition des constantes
#define TRUE 1
#define FALSE 0
#define EXIT "n"

// Vaeurs possibles pour les cartes
char valeurs[13] = { '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
		'E' };

// Type définissant un tableau associant chaque force symbolique au nombre de mains représentées
typedef struct ForceDistri {
	char* forceS;
	int nbMains;
} TypeForceDistri;

/**
 * Remplit le tableau listeMains à partir d'un fichier préalablement rempli
 *
 * @param char** listeMains: tableau contenant la liste de toutes les mains possibles au poker
 *
 * @return int 0 si tout se passe bien, -1 sinon
 */
int lireMains(char** listeMains) {
	FILE* fichier = NULL;
	// Modifiez cette ligne afin de lire le fichier contenant les mains au bon endroit
	fichier = fopen("/home/david/workspace/Poker/Debug/mains", "r");
	char main[10];
	if (fichier != NULL ) {
		for (int i = 0; i < 2598960; i++) {
			if (fgets(main, 11, fichier) != NULL ) {
				listeMains[i] = malloc(11 * sizeof(char));
				strcpy(listeMains[i], main);
				fseek(fichier, 10, (i - 1) * 10);
			} else {
				return -1;
			}
		}
		fclose(fichier);
		return 0;
	} else {
		printf("Erreur lors de l'ouverture du fichier\n");
		return -1;
	}
}

/**
 * Retourne la valeur numérique d'une carte
 *
 * @param char valeur: la valeur d'une carte
 *
 * @return int la valeur numérique d'une carte
 */
int rechercheCarte(char valeur) {
	int valeurNum, trouve;
	int i = 0;
	while (i < 13 && !trouve) {
		if (valeurs[i] == valeur) {
			valeurNum = i;
		}
		i++;
	}
	return valeurNum;
}

/**
 * Détermine si une main contient un carre et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* carre(char* main) {
	char* forceS = malloc(4);
	forceS[0] = '\0';
	if (((int) main[0] == (int) main[2] && (int) main[2] == (int) main[4]
			&& (int) main[4] == (int) main[6])
			|| ((int) main[2] == (int) main[4] && (int) main[4] == (int) main[6]
					&& (int) main[6] == (int) main[8])) {
		if ((int) main[0] != (int) main[2]) {
			sprintf(forceS, "8%c%c", main[2], main[0]);
		} else {
			sprintf(forceS, "8%c%c", main[2], main[8]);
		}
	}
	return forceS;
}

/**
 * Détermine si une main contient un full et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* full(char* main) {
	char* forceS = malloc(4);
	forceS[0] = '\0';
	if ((int) main[0] == (int) main[2] && (int) main[4] == (int) main[6]
			&& (int) main[6] == (int) main[8]) {
		sprintf(forceS, "7%c%c", main[4], main[0]);
	} else if ((int) main[0] == (int) main[2] && (int) main[2] == (int) main[4]
			&& (int) main[6] == (int) main[8]) {
		sprintf(forceS, "7%c%c", main[0], main[6]);
	}
	return forceS;
}

/**
 * Détermine si une main contient un flush et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* flush(char* main) {
	char* forceS = malloc(7);
	forceS[0] = '\0';
	if (main[1] == main[3] && main[3] == main[5] && main[5] == main[7]
			&& main[7] == main[9]) {
		sprintf(forceS, "6%c%c%c%c%c", main[0], main[2], main[4], main[6],
				main[8]);
	}
	return forceS;
}

/**
 * Détermine si une main contient une quinte et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* quinte(char* main) {
	char* forceS = malloc(3);
	forceS[0] = '\0';
	// On vérifie d'abbord s'il y a quinte avec l'as en premier (1,2,3,4,5)
	if ((int) main[0] == (int) '2' && (int) main[2] == (int) '3'
			&& (int) main[4] == (int) '4' && (int) main[6] == (int) '5'
			&& (int) main[8] == (int) 'E') {
		sprintf(forceS, "5%c", main[6]);
	}
	// On vérifie ensuite s'il y a une quinte "normale"
	for (int i = 0; i < 8; i += 2) {
		// On vérifie si les deux valeurs se suivent
		if ((rechercheCarte(main[i]) + 1) != rechercheCarte(main[i + 2])) {
			return forceS;
		}
	}
	sprintf(forceS, "5%c", main[8]);
	return forceS;
}

/**
 * Détermine si une main contient une quinte flush et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* quinteFlush(char* main) {
	char* forceS = malloc(3);
	forceS[0] = '\0';
	char* h = malloc(3);
	h = quinte(main);
	if (strcmp(flush(main), "") && strcmp(h, "")) {
		sprintf(forceS, "9%c", h[1]);
	}
	return forceS;
}

/**
 * Détermine si une main contient un brelan et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* brelan(char* main) {
	char* forceS = malloc(5);
	forceS[0] = '\0';
	if (main[0] == main[2] && main[2] == main[4]) {
		sprintf(forceS, "4%c%c%c", main[4], main[6], main[8]);
	} else if (main[2] == main[4] && main[4] == main[6]) {
		sprintf(forceS, "4%c%c%c", main[4], main[0], main[8]);
	} else if (main[4] == main[6] && main[6] == main[8]) {
		sprintf(forceS, "4%c%c%c", main[4], main[0], main[2]);
	}
	return forceS;
}

/**
 * Détermine si une main contient deux paires et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* deuxPaires(char* main) {
	char* forceS = malloc(5);
	forceS[0] = '\0';
	if ((int) main[0] == (int) main[2] && (int) main[4] == (int) main[6]) {
		sprintf(forceS, "3%c%c%c", main[0], main[4], main[8]);
	} else if ((int) main[2] == (int) main[4]
			&& (int) main[6] == (int) main[8]) {
		sprintf(forceS, "3%c%c%c", main[2], main[6], main[0]);
	} else if ((int) main[0] == (int) main[2]
			&& (int) main[6] == (int) main[8]) {
		sprintf(forceS, "3%c%c%c", main[0], main[6], main[4]);
	}
	return forceS;
}

/**
 * Détermine si une main contient une paire et retourne sa force symbolique
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* paire(char* main) {
	char* forceS = malloc(6);
	forceS[0] = '\0';
	if ((int) main[0] == (int) main[2]) {
		sprintf(forceS, "2%c%c%c%c", main[0], main[4], main[6], main[8]);
	} else if ((int) main[2] == (int) main[4]) {
		sprintf(forceS, "2%c%c%c%c", main[2], main[0], main[6], main[8]);
	} else if ((int) main[4] == (int) main[6]) {
		sprintf(forceS, "2%c%c%c%c", main[4], main[0], main[2], main[8]);
	} else if ((int) main[6] == (int) main[8]) {
		sprintf(forceS, "2%c%c%c%c", main[6], main[0], main[2], main[4]);
	}
	return forceS;
}

/**
 * Retourne la force symbolique d'une hauteur
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* le code correspondant à la main si celle-ci est reconnue, une chaine vide sinon
 */
char* hauteur(char* main) {
	char* forceS = malloc(7);
	forceS[0] = '\0';
	sprintf(forceS, "1%c%c%c%c%c", main[0], main[2], main[4], main[6], main[8]);
	return forceS;
}

/**
 * Calcule la force symbolique d'une main
 *
 * @param char* main: la main dont la force est à calculer
 *
 * @return char* la force symbolique de la main passée en paramètre
 */
char* calculeForceS(char* main) {
	char* forceS;
	if (strcmp(forceS = quinteFlush(main), "")) {
		return forceS;
	} else if (strcmp(forceS = carre(main), "")) {
		return forceS;
	} else if (strcmp(forceS = full(main), "")) {
		return forceS;
	} else if (strcmp(forceS = flush(main), "")) {
		return forceS;
	} else if (strcmp(forceS = quinte(main), "")) {
		return forceS;
	} else if (strcmp(forceS = brelan(main), "")) {
		return forceS;
	} else if (strcmp(forceS = deuxPaires(main), "")) {
		return forceS;
	} else if (strcmp(forceS = paire(main), "")) {
		return forceS;
	} else {
		return hauteur(main);
	}
}

/**
 * Calcule la force symbolique de chaque main
 *
 * @param char** listeMains: tableau contenant la liste de toutes les mains possibles au poker
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 */
void genererDistribution(char** listeMains, TypeForceDistri* distribution) {
	char* forceS;
	float fact;
	fact = (float) 100 / (float) 2598960;
	float pourc;
	for (int i = 0; i < 2598960; i++) {
		forceS = calculeForceS(listeMains[i]);

		//debug
		if (i % 1000 == 0) {
			pourc = i * fact;
			printf("Avancement de la génération: %.0f%%\r", pourc);
		}

		int test = FALSE;
		int j = 0;
		while (j < 7462 && !test) {
			if (!strcmp(distribution[j].forceS, "")) {
				strcpy(distribution[j].forceS, forceS);
				distribution[j].nbMains++;
				test = TRUE;
			} else if (!strcmp(distribution[j].forceS, forceS)) {
				distribution[j].nbMains++;
				test = TRUE;
			}
			j++;
		}
	}
}

/**
 * Trie le tableau de forces symboliques de la plus faible à la plus forte
 *
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 */
void triDistribution(TypeForceDistri* distribution) {
	int permutation = 1;
	char* forceTemp;
	int nbTemp;
	while (permutation == 1) {
		permutation = 0;
		for (int i = 0; i < 7461; i++) {
			if (strcmp(distribution[i].forceS, distribution[i + 1].forceS)
					> 0) {
				forceTemp = distribution[i + 1].forceS;
				nbTemp = distribution[i + 1].nbMains;
				distribution[i + 1].forceS = distribution[i].forceS;
				distribution[i + 1].nbMains = distribution[i].nbMains;
				distribution[i].forceS = forceTemp;
				distribution[i].nbMains = nbTemp;
				permutation = 1;
			}
		}
	}
}

/**
 * Calcule la force numerique d'une main à partir de sa force symbolique
 *
 * @param char* forceS: la force symbolique d'une main
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 *
 * @return int la force numérique correspondant à la force symbolique passée en paramètre
 */
int fsym2fnum(char* forceS, TypeForceDistri* distribution) {
	int trouve = FALSE;
	int i = 0;
	while (i < 7462 && !trouve) {
		if (!strcmp(distribution[i].forceS, forceS)) {
			trouve = TRUE;
		} else {
			i++;
		}
	}
	return i;
}

/**
 * Retourne vrai si une carte existe dans la main donnée
 *
 * @param char* carte: la carte à tester
 * @param char* main: la main à tester
 *
 * @return int 1 si la carte existe dans la main, 0 sinon
 */
int existeCarte(char* carte, char* main) {
	char* cartetmp = malloc(3);
	cartetmp[0] = '\0';
	int i = 0;
	int trouve = FALSE;
	while (i < 10 && !trouve) {
		sprintf(cartetmp, "%c%c", main[i], main[i + 1]);
		if (!strcmp(carte, cartetmp)) {
			trouve = TRUE;
		}
		i += 2;
	}
	return trouve;
}

/**
 * Calcule le nombre de mains battues à partir de deux cartes
 *
 * @param char* carte1: première carte de départ
 * @param char* carte2: seconde carte de départ
 * @param char** listeMains: tableau contenant la liste de toutes les mains possibles au poker
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 *
 * @return long le nombre de mains battues à partir de deux cartes
 */
long mainsBattues(char* carte1, char* carte2, char** listeMains,
		TypeForceDistri distribution[7462]) {
	long mains = 0;
	int forceN;
	int forceNMoy;
	int nbForces = 0;
	float fact;
	fact = (float) 100 / (float) 2598960;
	float pourc;
	for (int i = 0; i < 2598960; i++) {
		if (existeCarte(carte1, listeMains[i])
				&& existeCarte(carte2, listeMains[i])) {
			forceN = fsym2fnum(calculeForceS(listeMains[i]), distribution);
			forceNMoy += forceN;
			nbForces++;
		}
		if (i % 1000 == 0) {
			pourc = i * fact;
			printf("Calcul des mains battues: %.0f%%\r", pourc);
		}
	}
	forceNMoy = forceNMoy / nbForces;
	for (int j = 0; j < forceNMoy; j++) {
		mains += distribution[j].nbMains;
	}
	return mains;
}

/**
 * Fonction qui calcule le nombre de futurs possible à partir de deux cartes
 *
 * @param char* carte1: première carte de départ
 * @param char* carte2: seconde carte de départ
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 *
 * @return int le nombre de futurs possible à partir de deux cartes
 */
int futursPossibles(char* carte1, char* carte2, char** listeMains,
		TypeForceDistri distribution[7462]) {
	int nbfuturs = 0;
	float fact;
	fact = (float) 100 / (float) 2598960;
	float pourc;
	for (int i = 0; i < 2598960; i++) {
		if (existeCarte(carte1, listeMains[i])
				&& existeCarte(carte2, listeMains[i])) {
			nbfuturs++;
		}
		if (i % 1000 == 0) {
			pourc = i * fact;
			printf("Calcul des futurs possibles: %.0f%%\r", pourc);
		}
	}
	return nbfuturs;
}

/**
 * Fonction de test calculant le nombre de mains par force symbolique
 *
 * @param TypeForceDistri* distribution: tableau contenant les forces symboliques ainsi que le nombre de mains représentées par chaque force
 * @param int* nbForcesType: tableau contenant le nombre de mains par force symbolique
 */
void nbForcesByType(TypeForceDistri* distribution, int* nbForcesType) {
	for (int i = 0; i < 7462; i++) {
		if (distribution[i].forceS[0] == '1') {
			nbForcesType[0] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '2') {
			nbForcesType[1] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '3') {
			nbForcesType[2] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '4') {
			nbForcesType[3] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '5') {
			nbForcesType[4] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '6') {
			nbForcesType[5] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '7') {
			nbForcesType[6] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '8') {
			nbForcesType[7] += distribution[i].nbMains;
		} else if (distribution[i].forceS[0] == '9') {
			nbForcesType[8] += distribution[i].nbMains;
		}
	}
}

int main(int argc, char** argv) {
	char** listeMains = malloc(2598960 * sizeof(char*));
	if (lireMains(listeMains) < 0) {
		return -1;
	}
	TypeForceDistri distribution[7462];
	for (int i = 0; i < 7462; i++) {
		distribution[i].forceS = malloc(7);
		distribution[i].forceS[0] = '\0';
		distribution[i].nbMains = 0;
	}
	genererDistribution(listeMains, distribution);
	triDistribution(distribution);
	char* carte1 = malloc(3);
	char* carte2 = malloc(3);
	double proba;
	long mainsbattues;
	int futurspossibles = 0;
	char* choix = malloc(2);
	choix[0] = '\0';
	while (strcmp(EXIT, choix) != 0) {
		printf("\nEntrez votre première carte:\n");
		scanf("%s", carte1);
		printf("Entrez votre seconde carte:\n");
		scanf("%s", carte2);
		futurspossibles = futursPossibles(carte1, carte2, listeMains,
				distribution);
		printf("\n");
		mainsbattues = mainsBattues(carte1, carte2, listeMains, distribution);
		proba = (double) mainsbattues / (double) (futurspossibles + 2598960)
				* 100;
		printf("\nChances de gagner avec ces deux cartes: %.1f%%\n",
				mainsbattues, proba);
		printf("Souhaitez-vous continuer? y/n\n");
		scanf("%s", choix);
	}
	// libération de l'espace mémoire alloué
	free(listeMains);
	for (int i = 0; i < 7462; i++) {
		free(distribution[i].forceS);
	}
	free(carte1);
	free(carte2);
	return 0;
}
